package com.xy.service.calculate.maori;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.xy.api.constant.UnitConstant;
import com.xy.api.constant.enums.UnitTypeEnum;
import com.xy.api.exception.BizException;
import com.xy.api.model.dto.calculate.maori.MaoriProductInstanceDTO;
import com.xy.api.model.request.calculate.maori.SubmitMaoriProductInstanceRequest;
import com.xy.api.service.calculate.maori.IMaoriProductInstanceService;
import com.xy.api.service.calculate.maori.IMaoriProductService;
import com.xy.api.service.common.IUnitService;
import com.xy.mapper.calculate.maori.MaoriProductInstanceMapper;
import com.xy.mapper.calculate.maori.MaoriProductMapper;
import com.xy.model.condition.costing.CostingProductInstanceCondition;
import com.xy.model.po.calculate.maori.MaoriProductInstancePO;
import com.xy.model.po.calculate.maori.MaoriProductPO;
import com.xy.utils.CustomBeanUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;

import java.beans.Transient;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;

@Slf4j
@Service
public class MaoriProductInstanceServiceImpl implements IMaoriProductInstanceService {


    @Autowired
    private IMaoriProductService maoriProductService;

    @Autowired
    private MaoriProductMapper maoriProductMapper;

    @Autowired
    private MaoriProductInstanceMapper maoriProductInstanceMapper;

    @Autowired
    private IUnitService unitService;

    @Override
    public List<MaoriProductInstanceDTO> queryProductInstanceList(Long productId) {
        Assert.notNull(productId, "项目ID必填");
        CostingProductInstanceCondition instanceCondition = new CostingProductInstanceCondition();
        instanceCondition.setCostingProductId(productId);
        instanceCondition.setIsTotal(0);
        List<MaoriProductInstancePO> productInstancePOS = maoriProductInstanceMapper.queryList(instanceCondition);
        if (CollectionUtils.isEmpty(productInstancePOS)) {
            return new ArrayList<>();
        }
        List<MaoriProductInstanceDTO> list = CustomBeanUtil.copyListProperties(productInstancePOS, MaoriProductInstanceDTO::new);

        fillVolumeWeight(list, productId);
        return list;
    }

    /**
     * 填充体积重
     *
     * @param list
     * @param maoriProductId 核算实例ID
     */
    private void fillVolumeWeight(List<MaoriProductInstanceDTO> list, Long maoriProductId) {
        if (CollectionUtils.isEmpty(list)) {
            return;
        }
        MaoriProductPO maoriProductPO = maoriProductMapper.selectById(maoriProductId);
        Integer weightSpeedDivision = maoriProductPO.getWeightSpeedDivision();

        for (MaoriProductInstanceDTO maoriProductInstance : list) {
            BigDecimal volumeWeight = getVolumeWeight(maoriProductInstance, weightSpeedDivision);
            maoriProductInstance.setVolumeWeight(volumeWeight);
        }
    }

    @Override
    @Transient
    public void saveProductInstance(SubmitMaoriProductInstanceRequest request) {
        Long costingProductId = request.getCostingProductId();
        Assert.notEmpty(request.getInstanceList(), "提交数据不能为空");

        List<MaoriProductInstanceDTO> instanceList = request.getInstanceList();
        for (MaoriProductInstanceDTO instance : instanceList) {
            MaoriProductInstancePO record = new MaoriProductInstancePO();
            BeanUtils.copyProperties(instance, record);
            record.setCostingProductId(costingProductId);
            record.setIsTotal(0);
            if (null != instance.getId()) {
                maoriProductInstanceMapper.updateById(record);
            } else {
                maoriProductInstanceMapper.insert(record);
            }
        }
        maoriProductService.updateProductStatus(costingProductId, 0);
    }

    /**
     * 获取体积重
     *
     * @param maoriProductInstance
     * @param weightSpeedDivision
     * @return
     */
    private BigDecimal getVolumeWeight(MaoriProductInstanceDTO maoriProductInstance, Integer weightSpeedDivision) {
        BigDecimal packetLength = maoriProductInstance.getPacketLength();
        BigDecimal packetWidth = maoriProductInstance.getPacketWidth();
        BigDecimal packetHeight = maoriProductInstance.getPacketHeight();

        if (null != packetLength && null != packetWidth && null != packetHeight) {
            BigDecimal packetVolume = packetLength.multiply(packetWidth).multiply(packetHeight);
            if (null != weightSpeedDivision) {
                BigDecimal volumeWeight = packetVolume.divide(BigDecimal.valueOf(weightSpeedDivision), 2, RoundingMode.HALF_UP);
                return volumeWeight;
            }
        }
        return null;
    }

    /**
     * 获取海运重量取值
     *
     * @param maoriProductInstance
     * @param weightSpeedDivision
     * @return
     */
    private BigDecimal getOceanShipTakeWeight(MaoriProductInstanceDTO maoriProductInstance, Integer weightSpeedDivision) {
        BigDecimal packetTrueWeight = maoriProductInstance.getPacketTrueWeight();
        BigDecimal volumeWeight = getVolumeWeight(maoriProductInstance, weightSpeedDivision);
        if (null != volumeWeight && null != packetTrueWeight) {
            BigDecimal countWeight = packetTrueWeight.max(volumeWeight);
            return countWeight;
        }
        return null;
    }

    @Override
    public void deleteProductInstance(SubmitMaoriProductInstanceRequest request) {
        MaoriProductInstancePO deleteRecord = new MaoriProductInstancePO();
        deleteRecord.setId(request.getCostingProductInstanceId());
        deleteRecord.setIsDeleted(1);
        maoriProductInstanceMapper.updateById(deleteRecord);
    }

    @Override
    public void calculate(Long costingProductId) {
        maoriProductService.checkProduct(costingProductId);
        List<MaoriProductInstanceDTO> list = queryProductInstanceList(costingProductId);
        if (!CollectionUtils.isEmpty(list)) {
            checkProductInstance(list);
            MaoriProductPO productPO = maoriProductMapper.selectById(costingProductId);
            int totalPercent = 0;
            for (MaoriProductInstanceDTO instance : list) {
                Integer percent = null != instance.getPercent() ? instance.getPercent() : 0;
                totalPercent += percent;
                calculateCostingData(productPO, instance);
            }
            if (totalPercent == 100) {
                calculateTotal(costingProductId, list);
            }
        }
    }

    @Override
    public MaoriProductInstanceDTO queryTotalInstance(Long productId) {
        Assert.notNull(productId, "项目ID必填");
        LambdaQueryWrapper<MaoriProductInstancePO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(MaoriProductInstancePO::getIsDeleted, 0);
        queryWrapper.eq(MaoriProductInstancePO::getIsTotal, 1);
        queryWrapper.eq(MaoriProductInstancePO::getCostingProductId, productId);
        MaoriProductInstancePO totalInstance = maoriProductInstanceMapper.selectOne(queryWrapper);
        if (null == totalInstance) {
            throw new BizException("尚未核算完成");
        }
        MaoriProductInstanceDTO costingProductInstance = new MaoriProductInstanceDTO();
        CustomBeanUtil.copyProperties(totalInstance, costingProductInstance);
        return costingProductInstance;
    }

    /**
     * 核算前检查数据是否全部填写
     *
     * @param list
     */
    private void checkProductInstance(List<MaoriProductInstanceDTO> list) {
        if (CollectionUtils.isEmpty(list)) {
            throw new BizException("提交数据不能为空");
        }
        int allPercent = 0;
        for (MaoriProductInstanceDTO instance : list) {
            Integer percent = null != instance.getPercent() ? instance.getPercent() : 0;
            allPercent += percent;
            if (null == instance.getVariantCodeOneValue()) {
                throw new BizException("变体1 必填");
            }
            if (null == instance.getPercent()) {
                throw new BizException("占比 必填");
            }
            if (null == instance.getPurchaseCost()) {
                throw new BizException("采购成本 必填");
            }
            if (null == instance.getAdvertisingPer()) {
                throw new BizException("广告占比 必填");
            }
            if (null == instance.getDiscountPer()) {
                throw new BizException("折让占比 必填");
            }
            if (null == instance.getCommissionPer()) {
                throw new BizException("佣金占比 必填");
            }
            if (null == instance.getRefundPer()) {
                throw new BizException("退款占比");
            }
            if (null == instance.getPrice()) {
                throw new BizException("售价 必填");
            }
            if (null == instance.getProductLength()) {
                throw new BizException("产品-长 必填");
            }
            if (null == instance.getProductWidth()) {
                throw new BizException("产品-宽 必填");
            }
            if (null == instance.getProductHeight()) {
                throw new BizException("产品-高 必填");
            }
            if (null == instance.getOuterCartonPackCount()) {
                throw new BizException("装箱量 必填");
            }
            if (null == instance.getPacketLength()) {
                throw new BizException("装箱-长 必填");
            }
            if (null == instance.getPacketWidth()) {
                throw new BizException("装箱-宽 必填");
            }
            if (null == instance.getPacketHeight()) {
                throw new BizException("装箱-高 必填");
            }
            if (null == instance.getProductWeight()) {
                throw new BizException("单个产品净重 必填");
            }
            if (null == instance.getPackageWeight()) {
                throw new BizException("单个产品包装重 必填");
            }
            if (null == instance.getPacketTrueWeight()) {
                throw new BizException("整箱实重 必填");
            }
            if (null == instance.getDistributionCost()) {
                throw new BizException("配送费 必填");
            }
        }

//        if (Objects.equals(allPercent, 100)) {
//            throw new BizException("各项占比加起来不为100%");
//        }
    }

    private void calculateCostingData(MaoriProductPO product, MaoriProductInstanceDTO instance) {
        BigDecimal hundred = BigDecimal.valueOf(100);

        //采购成本占比
        String priceUnit = product.getPriceUnit();
        BigDecimal price = instance.getPrice();
        BigDecimal purchaseCost = instance.getPurchaseCost();
        purchaseCost = unitService.convertUnit(UnitTypeEnum.EXCHANGE_RATE.getCode(), UnitConstant.CurrencyUnitEnum.CNY.getCode(), priceUnit, purchaseCost);
        BigDecimal purchasePercent = purchaseCost.divide(price, 4, RoundingMode.HALF_UP).multiply(hundred);
        instance.setPurchasePercent(purchasePercent);

        //配送占比
        BigDecimal distributionCost = instance.getDistributionCost();
        BigDecimal distributionCostPercent = distributionCost.divide(price, 4, RoundingMode.HALF_UP).multiply(hundred);
        instance.setDistributionCostPercent(distributionCostPercent);

        //海运费用
        String weightUnit = product.getWeightUnit();
        //oceanShipPrice单位是（人民币/千克）
        BigDecimal oceanShipPrice = product.getOceanShipPrice();
        BigDecimal outerCartonPackCount = BigDecimal.valueOf(instance.getOuterCartonPackCount());
        BigDecimal oceanShipTakeWeight = getOceanShipTakeWeight(instance, product.getWeightSpeedDivision());
        oceanShipTakeWeight = unitService.convertUnit(UnitTypeEnum.WEIGHT.getCode(), weightUnit, UnitConstant.WeightUnitEnum.KG.getCode(), oceanShipTakeWeight);
        BigDecimal oceanShipCost = oceanShipTakeWeight.divide(outerCartonPackCount, 2, RoundingMode.HALF_UP).multiply(oceanShipPrice).setScale(2, RoundingMode.HALF_UP);
        instance.setOceanShipCost(oceanShipCost);

        //海运费占比
        oceanShipCost = unitService.convertUnit(UnitTypeEnum.EXCHANGE_RATE.getCode(), UnitConstant.CurrencyUnitEnum.CNY.getCode(), priceUnit, oceanShipCost);
        BigDecimal oceanShipPercent = oceanShipCost.divide(price, 4, RoundingMode.HALF_UP).multiply(hundred).setScale(2, RoundingMode.HALF_UP);
        instance.setOceanShipCostPercent(oceanShipPercent);

        //营销占比
        BigDecimal advertisingPer = instance.getAdvertisingPer();
        BigDecimal discountPer = instance.getDiscountPer();
        BigDecimal commissionPer = instance.getCommissionPer();
        commissionPer = (BigDecimal.valueOf(100).subtract(discountPer)).multiply(commissionPer).setScale(2, RoundingMode.HALF_UP).divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_UP);
        BigDecimal marketPercent = advertisingPer.add(discountPer).add(commissionPer).setScale(2, RoundingMode.HALF_UP);
        instance.setMarketPercent(marketPercent);

        //落地成本占比
        BigDecimal landingCostPercent = purchasePercent.add(oceanShipPercent).setScale(2, RoundingMode.HALF_UP);
        instance.setLandingCostPercent(landingCostPercent);

        //仓储费
        //仓储价格（美元/立方英尺）
        BigDecimal storagePrice = product.getStoragePrice();
        String productUnit = product.getProductUnit();

        BigDecimal packetLengthFT = unitService.convertUnit(UnitTypeEnum.LENGTH.getCode(), productUnit, UnitConstant.LengthUnitEnum.FT.getCode(), instance.getPacketLength());
        BigDecimal packetWidthFT = unitService.convertUnit(UnitTypeEnum.LENGTH.getCode(), productUnit, UnitConstant.LengthUnitEnum.FT.getCode(), instance.getPacketWidth());
        BigDecimal packetHeightFT = unitService.convertUnit(UnitTypeEnum.LENGTH.getCode(), productUnit, UnitConstant.LengthUnitEnum.FT.getCode(), instance.getPacketHeight());
        BigDecimal packetVolumeFT = getVolume(packetLengthFT, packetWidthFT, packetHeightFT);
        BigDecimal storageCost = packetVolumeFT.divide(outerCartonPackCount, 2, RoundingMode.HALF_UP).multiply(storagePrice);
        instance.setStorageCost(storageCost);

        //仓储占比
        BigDecimal storageCostPercent = storageCost.divide(price, 4, RoundingMode.HALF_UP).multiply(hundred);
        instance.setStorageCostPercent(storageCostPercent);

        //运营占比
        BigDecimal refundPer = instance.getRefundPer();
        BigDecimal operationPercent = distributionCostPercent.add(storageCostPercent).add(refundPer).setScale(2, RoundingMode.HALF_UP);
        instance.setOperationPercent(operationPercent);

        //回款率
        BigDecimal reimbursementRate = BigDecimal.valueOf(100).subtract(marketPercent).subtract(operationPercent).setScale(2, RoundingMode.HALF_UP);
        instance.setReimbursementRate(reimbursementRate);

        //利润率
        BigDecimal profitMargin = reimbursementRate.subtract(landingCostPercent).setScale(2, RoundingMode.HALF_UP);
        instance.setProfitMargin(profitMargin);
        MaoriProductInstancePO instanceRecord = new MaoriProductInstancePO();
        CustomBeanUtil.copyProperties(instance, instanceRecord);
        maoriProductInstanceMapper.updateById(instanceRecord);
    }

    /**
     * 计算体积
     *
     * @param length 长
     * @param width  宽
     * @param height 高
     * @return
     */
    private BigDecimal getVolume(BigDecimal length, BigDecimal width, BigDecimal height) {
        if (null == length || null == width || null == height) {
            return null;
        }
        return length.multiply(width).multiply(height).setScale(4, RoundingMode.HALF_UP);
    }

    /**
     * 计算总的数值
     *
     * @param costingProductId 项目ID
     * @param list
     */
    private void calculateTotal(Long costingProductId, List<MaoriProductInstanceDTO> list) {
        if (CollectionUtils.isEmpty(list)) {
            return;
        }
        MaoriProductInstancePO totalInstance = new MaoriProductInstancePO();

        //售价
        double price = 0;
        //利润率
        double profitMargin = 0;
        //落地占比
        double landingCostPercent = 0;
        //采购占比
        double purchasePercent = 0;
        //海运费占比
        double oceanShipCostPercent = 0;
        //采购成本
        double purchaseCost = 0;
        //海运费
        double oceanShipCost = 0;
        //营销占比
        double marketPercent = 0;
        //广告占比
        double advertisingPer = 0;
        //折让占比
        double discountPer = 0;
        //佣金占比
        double commissionPer = 0;
        //运营占比
        double operationPercent = 0;
        //配送占比
        double distributionCostPercent = 0;
        //退款占比
        double refundPer = 0;
        //仓储占比
        double storageCostPercent = 0;
        //仓储费
        double storageCost = 0;
        //配送费
        double distributionCost = 0;
        //回款率
        double reimbursementRate = 0;

        for (MaoriProductInstanceDTO instance : list) {
            double percent = (double) instance.getPercent() / 100;

            price += percent * instance.getPrice().doubleValue();
            profitMargin += percent * instance.getProfitMargin().doubleValue();
            landingCostPercent += percent * instance.getLandingCostPercent().doubleValue();
            purchasePercent += percent * instance.getPurchasePercent().doubleValue();
            oceanShipCostPercent += percent * instance.getOceanShipCostPercent().doubleValue();
            purchaseCost += percent * instance.getPurchaseCost().doubleValue();
            oceanShipCost += percent * instance.getOceanShipCost().doubleValue();
            marketPercent += percent * instance.getMarketPercent().doubleValue();
            advertisingPer += percent * instance.getAdvertisingPer().doubleValue();
            discountPer += percent * instance.getDiscountPer().doubleValue();
            commissionPer += percent * instance.getCommissionPer().doubleValue();
            operationPercent += percent * instance.getOperationPercent().doubleValue();
            distributionCostPercent += percent * instance.getDistributionCostPercent().doubleValue();
            refundPer += percent * instance.getRefundPer().doubleValue();
            storageCostPercent += percent * instance.getStorageCostPercent().doubleValue();
            storageCost += percent * instance.getStorageCost().doubleValue();
            distributionCost += percent * instance.getDistributionCost().doubleValue();
            reimbursementRate += percent * instance.getReimbursementRate().doubleValue();
        }


        totalInstance.setCostingProductId(costingProductId);
        totalInstance.setPercent(100);
        totalInstance.setIsTotal(1);
        totalInstance.setPrice(BigDecimal.valueOf(price).setScale(2, RoundingMode.HALF_UP));
        totalInstance.setProfitMargin(BigDecimal.valueOf(profitMargin).setScale(2, RoundingMode.HALF_UP));
        totalInstance.setLandingCostPercent(BigDecimal.valueOf(landingCostPercent).setScale(2, RoundingMode.HALF_UP));
        totalInstance.setPurchasePercent(BigDecimal.valueOf(purchasePercent).setScale(2, RoundingMode.HALF_UP));
        totalInstance.setOceanShipCostPercent(BigDecimal.valueOf(oceanShipCostPercent).setScale(2, RoundingMode.HALF_UP));
        totalInstance.setPurchaseCost(BigDecimal.valueOf(purchaseCost).setScale(2, RoundingMode.HALF_UP));
        totalInstance.setOceanShipCost(BigDecimal.valueOf(oceanShipCost).setScale(2, RoundingMode.HALF_UP));
        totalInstance.setMarketPercent(BigDecimal.valueOf(marketPercent).setScale(2, RoundingMode.HALF_UP));
        totalInstance.setAdvertisingPer(BigDecimal.valueOf(advertisingPer).setScale(2, RoundingMode.HALF_UP));
        totalInstance.setDiscountPer(BigDecimal.valueOf(discountPer).setScale(2, RoundingMode.HALF_UP));
        totalInstance.setCommissionPer(BigDecimal.valueOf(commissionPer).setScale(2, RoundingMode.HALF_UP));
        totalInstance.setOperationPercent(BigDecimal.valueOf(operationPercent).setScale(2, RoundingMode.HALF_UP));
        totalInstance.setDistributionCostPercent(BigDecimal.valueOf(distributionCostPercent).setScale(2, RoundingMode.HALF_UP));
        totalInstance.setRefundPer(BigDecimal.valueOf(refundPer).setScale(2, RoundingMode.HALF_UP));
        totalInstance.setStorageCost(BigDecimal.valueOf(storageCost).setScale(2, RoundingMode.HALF_UP));
        totalInstance.setStorageCostPercent(BigDecimal.valueOf(storageCostPercent).setScale(2, RoundingMode.HALF_UP));
        totalInstance.setDistributionCost(BigDecimal.valueOf(distributionCost).setScale(2, RoundingMode.HALF_UP));
        totalInstance.setReimbursementRate(BigDecimal.valueOf(reimbursementRate).setScale(2, RoundingMode.HALF_UP));

        CostingProductInstanceCondition instanceCondition = new CostingProductInstanceCondition();
        instanceCondition.setCostingProductId(costingProductId);
        instanceCondition.setIsTotal(1);
        List<MaoriProductInstancePO> existTotalInstanceList = maoriProductInstanceMapper.queryList(instanceCondition);
        if (CollectionUtils.isEmpty(existTotalInstanceList)) {
            maoriProductInstanceMapper.insert(totalInstance);
        } else {
            Long instanceId = existTotalInstanceList.get(0).getId();
            totalInstance.setId(instanceId);
            maoriProductInstanceMapper.updateById(totalInstance);
        }
        maoriProductService.updateProductStatus(costingProductId, 1);
    }

    @Override
    public MaoriProductInstanceDTO addInstance(MaoriProductInstanceDTO request) {
        MaoriProductInstancePO record = new MaoriProductInstancePO();
        CustomBeanUtil.copyProperties(request, record);
        maoriProductInstanceMapper.insert(record);

        MaoriProductInstanceDTO result = new MaoriProductInstanceDTO();
        CustomBeanUtil.copyProperties(record, result);
        return result;
    }
}
